#include "vsf.h"

#define MM32F103_FLASH_BASEADDR				0x08000000
#define MM32F103_FLASH_ADDR(addr)			(MM32F103_FLASH_BASEADDR + (addr))

#define MM32F103_FLASH_KEYR_KEY1			(uint32_t)0x45670123
#define MM32F103_FLASH_KEYR_KEY2			(uint32_t)0xCDEF89AB

#define VSFHAL_FLASH_NUM					1

#define FLASH_SR_ERR						(FLASH_SR_PGERR | FLASH_SR_WRPRTERR)

struct vsfhal_flash_t
{
	struct
	{
		void *param;
		void (*onfinish)(void*, vsf_err_t);
	} cb;
} static vsfhal_flash[VSFHAL_FLASH_NUM];

static vsf_err_t vsfhal_flash_checkidx(uint8_t index)
{
	return (index < VSFHAL_FLASH_NUM) ? VSFERR_NONE : VSFERR_NOT_SUPPORT;
}

vsf_err_t vsfhal_flash_capacity(uint8_t index, uint32_t *pagesize, uint32_t *pagenum)
{
	switch (index)
	{
	case 0:
		if (NULL != pagesize)
			*pagesize = 1024;
		if (NULL != pagenum)
			*pagenum = 128;
		return VSFERR_NONE;
	default:
		return VSFERR_NOT_SUPPORT;
	}
}

uint32_t vsfhal_flash_baseaddr(uint8_t index)
{
	return MM32F103_FLASH_BASEADDR;
}

// op -- operation: 0(ERASE), 1(READ), 2(WRITE)
uint32_t vsfhal_flash_blocksize(uint8_t index, uint32_t addr, uint32_t size, int op)
{
	uint32_t pagesize;
	if (vsfhal_flash_capacity(index, &pagesize, NULL))
		return 0;
	return !op ? pagesize : 2;
}

vsf_err_t vsfhal_flash_config_cb(uint8_t index, uint32_t int_priority,
		void *param, void (*onfinish)(void*, vsf_err_t))
{
	if (vsfhal_flash_checkidx(index))
		return VSFERR_NOT_SUPPORT;

	vsfhal_flash[index].cb.param = param;
	vsfhal_flash[index].cb.onfinish = onfinish;
	if (onfinish != NULL)
	{
		NVIC_SetPriority(FLASH_IRQn, int_priority);
		NVIC_EnableIRQ(FLASH_IRQn);
	}
	else
	{
		NVIC_DisableIRQ(FLASH_IRQn);
	}
	return VSFERR_NONE;
}

void vsfhal_flash_security_set(uint8_t index, uint8_t l0_h1)
{

}

vsf_err_t vsfhal_flash_init(uint8_t index)
{
	uint32_t size, pagenum;
	if (vsfhal_flash_capacity(index, &size, &pagenum))
		return VSFERR_FAIL;

	memset(vsfhal_flash, 0, sizeof(struct vsfhal_flash_t));

	FLASH->KEYR = MM32F103_FLASH_KEYR_KEY1;
	FLASH->KEYR = MM32F103_FLASH_KEYR_KEY2;
	FLASH->SR = FLASH_SR_PGERR | FLASH_SR_WRPRTERR | FLASH_SR_EOP;
	return VSFERR_NONE;
}

vsf_err_t vsfhal_flash_fini(uint8_t index)
{
	if (vsfhal_flash_checkidx(index))
		return VSFERR_NOT_SUPPORT;

	FLASH->CR |= FLASH_CR_LOCK;
	return VSFERR_NONE;
}

static vsf_err_t vsfhal_flash_finish(uint8_t index)
{
	if (!vsfhal_flash[index].cb.onfinish)
	{
		uint32_t sr;
		while (FLASH->SR & FLASH_SR_BSY);
		FLASH->CR &= ~(FLASH_CR_PER | FLASH_CR_PG | FLASH_CR_EOPIE);
		sr = FLASH->SR;
		FLASH->SR = sr;
		return (sr & FLASH_SR_ERR) ? VSFERR_FAIL : VSFERR_NONE;
	}
	return VSFERR_NONE;
}

vsf_err_t vsfhal_flash_erase(uint8_t index, uint32_t addr)
{
	switch (index)
	{
	case 0:
		if (FLASH->SR & FLASH_SR_BSY)
			return VSFERR_NOT_READY;

		FLASH->CR |= FLASH_CR_PER | FLASH_CR_EOPIE;
		FLASH->AR = MM32F103_FLASH_ADDR(addr);
		FLASH->CR |= FLASH_CR_STRT;
		break;
	default:
		return VSFERR_NOT_SUPPORT;
	}

	return vsfhal_flash_finish(index);
}

vsf_err_t vsfhal_flash_read(uint8_t index, uint32_t addr, uint8_t *buff)
{
	return VSFERR_NOT_SUPPORT;
}

vsf_err_t vsfhal_flash_write(uint8_t index, uint32_t addr, uint8_t *buff)
{
	switch (index)
	{
	case 0:
		if (FLASH->SR & FLASH_SR_BSY)
			return VSFERR_NOT_READY;

		FLASH->CR |= FLASH_CR_PG | FLASH_CR_EOPIE;
		*(uint16_t *)MM32F103_FLASH_ADDR(addr) =  *(uint16_t *)buff;
		break;
	default:
		return VSFERR_NOT_SUPPORT;
	}

	return vsfhal_flash_finish(index);
}

ROOTFUNC void FLASH_IRQHandler(void)
{
	FLASH->CR &= ~(FLASH_CR_PG | FLASH_CR_PER | FLASH_CR_EOPIE);
	if (vsfhal_flash[0].cb.onfinish != NULL)
	{
		vsfhal_flash[0].cb.onfinish(vsfhal_flash[0].cb.param,
				(FLASH->SR & FLASH_SR_ERR) ? VSFERR_FAIL : VSFERR_NONE);
	}
	FLASH->SR = FLASH->SR;
}
